/*******************************************************************************
 * Copyright (c) 2003, 2015 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.application;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.internal.StartupThreading;
import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
import org.eclipse.ui.internal.UISynchronizer;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.WorkbenchWindowConfigurer;
import org.eclipse.ui.internal.application.CompatibilityWorkbenchWindowAdvisor;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.model.ContributionComparator;
import org.eclipse.ui.model.IContributionService;
import org.eclipse.ui.statushandlers.AbstractStatusHandler;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.statushandlers.WorkbenchErrorHandler;

/**
 * Public base class for configuring the workbench.
 * <p>
 * Note that the workbench advisor object is created in advance of creating the
 * workbench. However, by the time the workbench starts calling methods on this
 * class, <code>PlatformUI.getWorkbench</code> is guaranteed to have been
 * properly initialized.
 * </p>
 * <p>
 * Example of creating and running a workbench (in an
 * <code>IPlatformRunnable</code>):
 *
 * <pre>
 * <code>
 *           public class MyApplication implements IPlatformRunnable {
 *             public Object run(Object args) {
 *               WorkbenchAdvisor workbenchAdvisor = new MyWorkbenchAdvisor();
 *               Display display = PlatformUI.createDisplay();
 *               int returnCode = PlatformUI.createAndRunWorkbench(display, workbenchAdvisor);
 *               if (returnCode == PlatformUI.RETURN_RESTART) {
 *                  return IPlatformRunnable.EXIT_RESTART;
 *               } else {
 *                  return IPlatformRunnable.EXIT_OK;
 *             }
 *           }
 * </code>
 * </pre>
 *
 * </p>
 * <p>
 * An application should declare a subclass of <code>WorkbenchAdvisor</code>
 * and override methods to configure the workbench to suit the needs of the
 * particular application.
 * </p>
 * <p>
 * The following advisor methods are called at strategic points in the
 * workbench's lifecycle (all occur within the dynamic scope of the call to
 * {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}):
 * <ul>
 * <li><code>initialize</code> - called first; before any windows; use to
 * register things</li>
 * <li><code>preStartup</code> - called second; after initialize but before
 * first window is opened; use to temporarily disable things during startup or
 * restore</li>
 * <li><code>postStartup</code> - called third; after first window is opened;
 * use to reenable things temporarily disabled in previous step</li>
 * <li><code>postRestore</code> - called after the workbench and its windows
 * has been recreated from a previously saved state; use to adjust the restored
 * workbench</li>
 * <li><code>preWindowOpen</code> - called as each window is being opened;
 * use to configure aspects of the window other than actions bars </li>
 * <li><code>fillActionBars</code> - called after <code>preWindowOpen</code>
 * to configure a window's action bars</li>
 * <li><code>postWindowRestore</code> - called after a window has been
 * recreated from a previously saved state; use to adjust the restored window</li>
 * <li><code>postWindowCreate</code> - called after a window has been
 * created, either from an initial state or from a restored state; used to
 * adjust the window</li>
 * <li><code>openIntro</code> - called immediately before a window is opened
 * in order to create the introduction component, if any.</li>
 * <li><code>postWindowOpen</code> - called after a window has been opened;
 * use to hook window listeners, etc.</li>
 * <li><code>preWindowShellClose</code> - called when a window's shell is
 * closed by the user; use to pre-screen window closings</li>
 * <li><code>eventLoopException</code> - called to handle the case where the
 * event loop has crashed; use to inform the user that things are not well</li>
 * <li><code>eventLoopIdle</code> - called when there are currently no more
 * events to be processed; use to perform other work or to yield until new
 * events enter the queue</li>
 * <li><code>preShutdown</code> - called immediately prior to workbench
 * shutdown before any windows have been closed; allows the advisor to veto the
 * shutdown</li>
 * <li><code>postShutdown</code> - called last; after event loop has
 * terminated and all windows have been closed; use to deregister things
 * registered during initialize</li>
 * </ul>
 * </p>
 *
 * @since 3.0
 */
public abstract class WorkbenchAdvisor {

	/**
	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
	 * operation is not filling the action bars of an actual workbench window,
	 * but rather a proxy (used for perspective customization).
	 *
	 * @deprecated use {@link ActionBarAdvisor#FILL_PROXY instead}
	 */
	@Deprecated
	public static final int FILL_PROXY = ActionBarAdvisor.FILL_PROXY;

	/**
	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
	 * operation is supposed to fill (or describe) the workbench window's menu
	 * bar.
	 *
	 * @deprecated use {@link ActionBarAdvisor#FILL_MENU_BAR instead}
	 */
	@Deprecated
	public static final int FILL_MENU_BAR = ActionBarAdvisor.FILL_MENU_BAR;

	/**
	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
	 * operation is supposed to fill (or describe) the workbench window's cool
	 * bar.
	 *
	 * @deprecated use {@link ActionBarAdvisor#FILL_COOL_BAR instead}
	 */
	@Deprecated
	public static final int FILL_COOL_BAR = ActionBarAdvisor.FILL_COOL_BAR;

	/**
	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
	 * operation is supposed to fill (or describe) the workbench window's status
	 * line.
	 *
	 * @deprecated use {@link ActionBarAdvisor#FILL_STATUS_LINE instead}
	 */
	@Deprecated
	public static final int FILL_STATUS_LINE = ActionBarAdvisor.FILL_STATUS_LINE;

	/**
	 * The workbench configurer.
	 */
	private IWorkbenchConfigurer workbenchConfigurer;

	/**
	 * The workbench error handler.
	 */
	private AbstractStatusHandler workbenchErrorHandler;

	private boolean introOpened;

	/**
	 * Creates and initializes a new workbench advisor instance.
	 */
	protected WorkbenchAdvisor() {
		// do nothing
	}

	/**
	 * Remembers the configurer and calls <code>initialize</code>.
	 * <p>
	 * For internal use by the workbench only.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the workbench
	 */
	public final void internalBasicInitialize(IWorkbenchConfigurer configurer) {
		if (workbenchConfigurer != null) {
			throw new IllegalStateException();
		}
		this.workbenchConfigurer = configurer;
		initialize(configurer);
	}

	/**
	 * Performs arbitrary initialization before the workbench starts running.
	 * <p>
	 * This method is called during workbench initialization prior to any
	 * windows being opened. Clients must not call this method directly
	 * (although super calls are okay). The default implementation does nothing.
	 * Subclasses may override. Typical clients will use the configurer passed
	 * in to tweak the workbench. If further tweaking is required in the future,
	 * the configurer may be obtained using <code>getWorkbenchConfigurer</code>.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the workbench
	 */
	public void initialize(IWorkbenchConfigurer configurer) {
		// do nothing
	}

	/**
	 * Returns the workbench configurer for the advisor. Can be
	 * <code>null</code> if the advisor is not initialized yet.
	 *
	 * @return the workbench configurer, or <code>null</code> if the advisor
	 *         is not initialized yet
	 */
	protected IWorkbenchConfigurer getWorkbenchConfigurer() {
		return workbenchConfigurer;
	}

	/**
	 * Returns the workbench error handler for the advisor.
	 *
	 * @return the workbench error handler
	 * @since 3.3
	 */
	public synchronized AbstractStatusHandler getWorkbenchErrorHandler() {
		if (workbenchErrorHandler == null) {
			workbenchErrorHandler = new WorkbenchErrorHandler();
		}
		return workbenchErrorHandler;
	}

	/**
	 * Performs arbitrary actions just before the first workbench window is
	 * opened (or restored).
	 * <p>
	 * This method is called after the workbench has been initialized and just
	 * before the first window is about to be opened. Clients must not call this
	 * method directly (although super calls are okay). The default
	 * implementation does nothing. Subclasses may override.
	 * </p>
	 */
	public void preStartup() {
		// do nothing
	}

	/**
	 * Performs arbitrary actions after the workbench windows have been opened
	 * (or restored), but before the main event loop is run.
	 * <p>
	 * This method is called just after the windows have been opened. Clients
	 * must not call this method directly (although super calls are okay). The
	 * default implementation does nothing. Subclasses may override. It is okay
	 * to call <code>IWorkbench.close()</code> from this method.
	 * </p>
	 */
	public void postStartup() {
		// do nothing
	}

	/**
	 * Performs arbitrary finalization before the workbench is about to shut
	 * down.
	 * <p>
	 * This method is called immediately prior to workbench shutdown before any
	 * windows have been closed. Clients must not call this method directly
	 * (although super calls are okay). The default implementation returns
	 * <code>true</code>. Subclasses may override.
	 * </p>
	 * <p>
	 * The advisor may veto a regular shutdown by returning <code>false</code>,
	 * although this will be ignored if the workbench is being forced to shut
	 * down.
	 * </p>
	 *
	 * @return <code>true</code> to allow the workbench to proceed with
	 *         shutdown, <code>false</code> to veto a non-forced shutdown
	 */
	public boolean preShutdown() {
		return true;
	}

	/**
	 * Performs arbitrary finalization after the workbench stops running.
	 * <p>
	 * This method is called during workbench shutdown after all windows have
	 * been closed. Clients must not call this method directly (although super
	 * calls are okay). The default implementation does nothing. Subclasses may
	 * override.
	 * </p>
	 */
	public void postShutdown() {
		// do nothing
	}

	/**
	 * Performs arbitrary actions when the event loop crashes (the code that
	 * handles a UI event throws an exception that is not caught).
	 * <p>
	 * This method is called when the code handling a UI event throws an
	 * exception. In a perfectly functioning application, this method would
	 * never be called. In practice, it comes into play when there are bugs in
	 * the code that trigger unchecked runtime exceptions. It is also activated
	 * when the system runs short of memory, etc. Fatal errors (ThreadDeath) are
	 * not passed on to this method, as there is nothing that could be done.
	 * </p>
	 * <p>
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation logs the problem so that it does not go
	 * unnoticed. Subclasses may override or extend this method. It is generally
	 * a bad idea to override with an empty method, and you should be especially
	 * careful when handling Errors.
	 * </p>
	 *
	 * @param exception
	 *            the uncaught exception that was thrown inside the UI event
	 *            loop
	 */
	public void eventLoopException(Throwable exception) {
		// Protection from client doing super(null) call
		if (exception == null) {
			return;
		}

		try {
			StatusManager.getManager().handle(
					new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
							"Unhandled event loop exception", exception)); //$NON-NLS-1$

			if (WorkbenchPlugin.DEBUG) {
				exception.printStackTrace();
			}
		} catch (Throwable e) {
			// One of the log listeners probably failed. Core should have logged
			// the
			// exception since its the first listener.
			System.err.println("Error while logging event loop exception:"); //$NON-NLS-1$
			exception.printStackTrace();
			System.err.println("Logging exception:"); //$NON-NLS-1$
			e.printStackTrace();
		}
	}

	/**
	 * Performs arbitrary work or yields when there are no events to be
	 * processed.
	 * <p>
	 * This method is called when there are currently no more events on the
	 * queue to be processed at the moment.
	 * </p>
	 * <p>
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation yields until new events enter the
	 * queue. Subclasses may override or extend this method. It is generally a
	 * bad idea to override with an empty method. It is okay to call
	 * <code>IWorkbench.close()</code> from this method.
	 * </p>
	 *
	 * @param display
	 *            the main display of the workbench UI
	 */
	public void eventLoopIdle(Display display) {
		// default: yield cpu until new events enter the queue
		display.sleep();
	}

	/**
	 * Creates a new workbench window advisor for configuring a new workbench
	 * window via the given workbench window configurer. Clients should override
	 * to provide their own window configurer. This method replaces all the
	 * other window and action bar lifecycle methods on the workbench advisor.
	 * <p>
	 * The default implementation creates a window advisor that calls back to
	 * the legacy window and action bar lifecycle methods on the workbench
	 * advisor, for backwards compatibility with 3.0.
	 * </p>
	 *
	 * @param configurer
	 *            the workbench window configurer
	 * @return a new workbench window advisor
	 * @since 3.1
	 */
	public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
			IWorkbenchWindowConfigurer configurer) {
		return new CompatibilityWorkbenchWindowAdvisor(this, configurer);
	}

	/**
	 * Performs arbitrary actions before the given workbench window is opened.
	 * <p>
	 * This method is called before the window's controls have been created.
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation does nothing. Subclasses may override.
	 * Typical clients will use the configurer passed in to tweak the workbench
	 * window in an application-specific way; however, filling the window's menu
	 * bar, tool bar, and status line must be done in
	 * {@link #fillActionBars fillActionBars}, which is called immediately
	 * after this method is called.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the particular workbench window
	 *            being opened
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#preWindowOpen()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void preWindowOpen(IWorkbenchWindowConfigurer configurer) {
		// do nothing
	}

	/**
	 * Configures the action bars using the given action bar configurer. Under
	 * normal circumstances, <code>flags</code> does not include
	 * <code>FILL_PROXY</code>, meaning this is a request to fill the
	 * actions\ bars of the given workbench window; the remaining flags indicate
	 * which combination of the menu bar (<code>FILL_MENU_BAR</code>), the
	 * tool bar (<code>FILL_COOL_BAR</code>), and the status line (<code>FILL_STATUS_LINE</code>)
	 * are to be filled.
	 * <p>
	 * If <code>flags</code> does include <code>FILL_PROXY</code>, then
	 * this is a request to describe the actions bars of the given workbench
	 * window (which will already have been filled); again, the remaining flags
	 * indicate which combination of the menu bar, the tool bar, and the status
	 * line are to be described. The actions included in the proxy action bars
	 * can be the same instances as in the actual window's action bars. Calling
	 * <code>ActionFactory</code> to create new action instances is not
	 * recommended, because these actions internally register listeners with the
	 * window and there is no opportunity to dispose of these actions.
	 * </p>
	 * <p>
	 * This method is called just after {@link #preWindowOpen preWindowOpen}.
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation does nothing. Subclasses may override.
	 * </p>
	 *
	 * @param window
	 *            the workbench window
	 * @param configurer
	 *            the action bar configurer object
	 * @param flags
	 *            bit mask composed from the constants
	 *            {@link #FILL_MENU_BAR FILL_MENU_BAR},
	 *            {@link #FILL_COOL_BAR FILL_COOL_BAR},
	 *            {@link #FILL_STATUS_LINE FILL_STATUS_LINE}, and
	 *            {@link #FILL_PROXY FILL_PROXY} Note: should 1st param be
	 *            IWorkbenchWindowConfigurer to be more consistent with other
	 *            methods? Note: suggest adding ActionBuilder as API, to
	 *            encapsulate the action building outside of the advisor, and to
	 *            handle the common pattern of hanging onto the action builder
	 *            in order to properly handle FILL_PROXY
	 *
	 * @deprecated since 3.1, override
	 *             {@link ActionBarAdvisor#fillActionBars(int)} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer)
	 */
	@Deprecated
	public void fillActionBars(IWorkbenchWindow window,
			IActionBarConfigurer configurer, int flags) {
		// do nothing by default
	}

	/**
	 * Performs arbitrary actions after the given workbench window has been
	 * restored, but before it is opened.
	 * <p>
	 * This method is called after a previously-saved window have been
	 * recreated. This method is not called when a new window is created from
	 * scratch. This method is never called when a workbench is started for the
	 * very first time, or when workbench state is not saved or restored.
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation does nothing. Subclasses may override.
	 * It is okay to call <code>IWorkbench.close()</code> from this method.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the particular workbench window just
	 *            restored
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#postWindowRestore()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void postWindowRestore(IWorkbenchWindowConfigurer configurer)
			throws WorkbenchException {
		// do nothing
	}

	/**
	 * Opens the introduction componenet.
	 * <p>
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation opens the intro in the first window
	 * provided the preference IWorkbenchPreferences.SHOW_INTRO is
	 * <code>true</code>. If an intro is shown then this preference will be
	 * set to <code>false</code>. Subsequently, and intro will be shown only
	 * if <code>WorkbenchConfigurer.getSaveAndRestore()</code> returns
	 * <code>true</code> and the introduction was visible on last shutdown.
	 * Subclasses may override.
	 * </p>
	 *
	 * @param configurer
	 *            configurer an object for configuring the particular workbench
	 *            window just created
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#openIntro()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void openIntro(IWorkbenchWindowConfigurer configurer) {
		if (introOpened) {
			return;
		}

		introOpened = true;

		boolean showIntro = PrefUtil.getAPIPreferenceStore().getBoolean(
				IWorkbenchPreferenceConstants.SHOW_INTRO);

		if (!showIntro) {
			return;
		}

		if (getWorkbenchConfigurer().getWorkbench().getIntroManager()
				.hasIntro()) {
			PrefUtil.getAPIPreferenceStore().setValue(
					IWorkbenchPreferenceConstants.SHOW_INTRO, false);
			PrefUtil.saveAPIPrefs();

			getWorkbenchConfigurer().getWorkbench().getIntroManager()
					.showIntro(configurer.getWindow(), false);
		}
	}

	/**
	 * Performs arbitrary actions after the given workbench window has been
	 * created (possibly after being restored), but has not yet been opened.
	 * <p>
	 * This method is called after a new window has been created from scratch,
	 * or when a previously-saved window has been restored. In the latter case,
	 * this method is called after <code>postWindowRestore</code>. Clients
	 * must not call this method directly (although super calls are okay). The
	 * default implementation does nothing. Subclasses may override.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the particular workbench window just
	 *            created
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#postWindowCreate()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void postWindowCreate(IWorkbenchWindowConfigurer configurer) {
		// do nothing
	}

	/**
	 * Performs arbitrary actions after the given workbench window has been
	 * opened (possibly after being restored).
	 * <p>
	 * This method is called after a window has been opened. This method is
	 * called after a new window has been created from scratch, or when a
	 * previously-saved window has been restored. Clients must not call this
	 * method directly (although super calls are okay). The default
	 * implementation does nothing. Subclasses may override.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the particular workbench window just
	 *            opened
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#postWindowOpen()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void postWindowOpen(IWorkbenchWindowConfigurer configurer) {
		// do nothing
	}

	/**
	 * Performs arbitrary actions as the given workbench window's shell is being
	 * closed directly, and possibly veto the close.
	 * <p>
	 * This method is called from a ShellListener associated with the workbench
	 * window. It is not called when the window is being closed for other
	 * reasons. Clients must not call this method directly (although super calls
	 * are okay). The default implementation does nothing. Subclasses may
	 * override. Typical clients may use the configurer passed in to access the
	 * workbench window being closed. If this method returns <code>false</code>,
	 * then the user's request to close the shell is ignored. This gives the
	 * workbench advisor an opportunity to query the user and/or veto the
	 * closing of a window under some circumstances.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the particular workbench window
	 *            whose shell is being closed
	 * @return <code>true</code> to allow the window to close, and
	 *         <code>false</code> to prevent the window from closing
	 * @see org.eclipse.ui.IWorkbenchWindow#close
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#preWindowShellClose()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public boolean preWindowShellClose(IWorkbenchWindowConfigurer configurer) {
		// do nothing, but allow the close() to proceed
		return true;
	}

	/**
	 * Performs arbitrary actions after the given workbench window is closed.
	 * <p>
	 * This method is called after the window's controls have been disposed.
	 * Clients must not call this method directly (although super calls are
	 * okay). The default implementation does nothing. Subclasses may override.
	 * Typical clients will use the configurer passed in to tweak the workbench
	 * window in an application-specific way.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the particular workbench window
	 *            being closed
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#postWindowClose()} instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void postWindowClose(IWorkbenchWindowConfigurer configurer) {
		// do nothing
	}

	/**
	 * Returns whether the menu with the given id is an application menu of the
	 * given window. This is used during OLE "in place" editing. Application
	 * menus should be preserved during menu merging. All other menus may be
	 * removed from the window.
	 * <p>
	 * The default implementation returns false. Subclasses may override.
	 * </p>
	 *
	 * @param configurer
	 *            an object for configuring the workbench window
	 * @param menuId
	 *            the menu id
	 * @return <code>true</code> for application menus, and <code>false</code>
	 *         for part-specific menus
	 *
	 * @deprecated since 3.1, override
	 *             {@link ActionBarAdvisor#isApplicationMenu(String)} instead
	 * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer)
	 */
	@Deprecated
	public boolean isApplicationMenu(IWorkbenchWindowConfigurer configurer,
			String menuId) {
		// default: not an application menu
		return false;
	}

	/**
	 * Returns the default input for newly created workbench pages when the
	 * input is not explicitly specified.
	 * <p>
	 * The default implementation returns <code>null</code>. Subclasses may
	 * override.
	 * </p>
	 *
	 * @return the default input for a new workbench window page, or
	 *         <code>null</code> if none
	 *
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	public IAdaptable getDefaultPageInput() {
		// default: no input
		return null;
	}

	/**
	 * Returns the id of the perspective to use for the initial workbench
	 * window, or <code>null</code> if no initial perspective should be shown
	 * in the initial workbench window.
	 * <p>
	 * This method is called during startup when the workbench is creating the
	 * first new window. Subclasses must implement.
	 * </p>
	 * <p>
	 * If the {@link IWorkbenchPreferenceConstants#DEFAULT_PERSPECTIVE_ID}
	 * preference is specified, it supercedes the perspective specified here.
	 * </p>
	 *
	 * @return the id of the perspective for the initial window, or
	 *         <code>null</code> if no initial perspective should be shown
	 */
	public abstract String getInitialWindowPerspectiveId();

	/**
	 * Returns the id of the preference page that should be presented most
	 * prominently.
	 * <p>
	 * The default implementation returns <code>null</code>. Subclasses may
	 * override.
	 * </p>
	 *
	 * @return the id of the preference page, or <code>null</code> if none
	 */
	public String getMainPreferencePageId() {
		// default: no opinion
		return null;
	}

	/**
	 * Creates the contents of the window.
	 * <p>
	 * The default implementation adds a menu bar, a cool bar, a status line, a
	 * perspective bar, and a fast view bar. The visibility of these controls
	 * can be configured using the <code>setShow*</code> methods on
	 * <code>IWorkbenchWindowConfigurer</code>.
	 * </p>
	 * <p>
	 * Subclasses may override to define custom window contents and layout, but
	 * must call <code>IWorkbenchWindowConfigurer.createPageComposite</code>.
	 * </p>
	 *
	 * @param configurer
	 *            the window configurer
	 * @param shell
	 *            the window's shell
	 * @see IWorkbenchWindowConfigurer#createMenuBar
	 * @see IWorkbenchWindowConfigurer#createCoolBarControl
	 * @see IWorkbenchWindowConfigurer#createStatusLineControl
	 * @see IWorkbenchWindowConfigurer#createPageComposite
	 *
	 * @deprecated since 3.1, override
	 *             {@link WorkbenchWindowAdvisor#createWindowContents(Shell)}
	 *             instead
	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
	 */
	@Deprecated
	public void createWindowContents(IWorkbenchWindowConfigurer configurer,
			Shell shell) {
		((WorkbenchWindowConfigurer) configurer).createDefaultContents(shell);
	}

	private volatile boolean initDone = false;

	/**
	 * Opens the workbench windows on startup. The default implementation tries
	 * to restore the previously saved workbench state using
	 * <code>IWorkbenchConfigurer.restoreWorkbenchState()</code>. If there
	 * was no previously saved state, or if the restore failed, then a
	 * first-time window is opened using
	 * <code>IWorkbenchConfigurer.openFirstTimeWindow</code>.
	 *
	 * @return <code>true</code> to proceed with workbench startup, or
	 *         <code>false</code> to exit
	 */
	public boolean openWindows() {
		final Display display = PlatformUI.getWorkbench().getDisplay();
		final boolean result [] = new boolean[1];

		// spawn another init thread.  For API compatibility We guarantee this method is called from
		// the UI thread but it could take enough time to disrupt progress reporting.
		// spawn a new thread to do the grunt work of this initialization and spin the event loop
		// ourselves just like it's done in Workbench.

		final Throwable [] error = new Throwable[1];
		Thread initThread = new Thread() {
			@Override
			public void run() {
				try {
					//declare us to be a startup thread so that our syncs will be executed
					UISynchronizer.startupThread.set(Boolean.TRUE);
					final IWorkbenchConfigurer [] myConfigurer = new IWorkbenchConfigurer[1];
					StartupThreading.runWithoutExceptions(new StartupRunnable() {

						@Override
						public void runWithException() throws Throwable {
							myConfigurer[0] = getWorkbenchConfigurer();

						}});

					IStatus status = myConfigurer[0].restoreState();
					if (!status.isOK()) {
						if (status.getCode() == IWorkbenchConfigurer.RESTORE_CODE_EXIT) {
							result[0] = false;
							return;
						}
						if (status.getCode() == IWorkbenchConfigurer.RESTORE_CODE_RESET) {
							myConfigurer[0].openFirstTimeWindow();
						}
					}
					result[0] = true;
				} catch (Throwable e) {
					error[0] = e;
				}
				finally {
					initDone = true;
					yield();
					try {
						Thread.sleep(5);
					} catch (InterruptedException e) {
						// this is a no-op in this case.
					}
					display.wake();
				}
			}};
			RWT.getUISession(display).exec(initThread);

		while (true) {
			if (!display.readAndDispatch()) {
				if (initDone)
					break;
				display.sleep();
			}

		}

			// can only be a runtime or error
			if (error[0] instanceof Error)
				throw (Error)error[0];
			else if (error[0] instanceof RuntimeException)
				throw (RuntimeException)error[0];

			return result[0];
	}

	/**
	 * Saves arbitrary application-specific state information for this workbench
	 * advisor.
	 * <p>
	 * The default implementation simply returns an OK status. Subclasses may
	 * extend or override.
	 * </p>
	 *
	 * @param memento
	 *            the memento in which to save the advisor's state
	 * @return a status object indicating whether the save was successful
	 * @since 3.1
	 */
	public IStatus saveState(IMemento memento) {
		return Status.OK_STATUS;
	}

	/**
	 * Restores arbitrary application-specific state information for this
	 * workbench advisor.
	 * <p>
	 * The default implementation simply returns an OK status. Subclasses may
	 * extend or override.
	 * </p>
	 *
	 * @param memento
	 *            the memento from which to restore the advisor's state
	 * @return a status object indicating whether the restore was successful
	 * @since 3.1
	 */
	public IStatus restoreState(IMemento memento) {
		return Status.OK_STATUS;
	}

	/**
	 * Return the contribution comparator for the particular type of
	 * contribution. The default implementation of this class returns a
	 * comparator that sorts the items by label.
	 *
	 * The contributionType may be one of the constants in
	 * {@link IContributionService} or it can be a value defined by the user.
	 *
	 * @param contributionType
	 *            the contribution type
	 * @return the comparator, must not return <code>null</code>
	 * @see IContributionService#getComparatorFor(String)
	 * @since 3.4
	 */
	public ContributionComparator getComparatorFor(String contributionType) {
		return new ContributionComparator();
	}
}